﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StarcraftBot.Wrapper;
using StarcraftBot;

namespace StarcraftBot {
    class BotEvents {
        public static bool OnSendText(string text) {
            Logger.AddAndPrint("you typed: " + text);
            return true;
        }


        static Unit scv = null;
        static Unit commandCenter = null;

        public static void OnStart() {
            // Warning: to run this example bot must be played as terran

            Logger.AddAndPrint("");
            Logger.AddAndPrint("");
            Logger.AddAndPrint("");
            Logger.AddAndPrint("***************************************************");
            Logger.AddAndPrint("New game start");
            Logger.AddAndPrint("***************************************************");
            Game.EnableUserInput(); // enable user input

            // There are some problems to run this method async
            // seems like some bwapi methods are not thread safe
            // map analyzing takes some time (30 secs or more) and then saves result to file
            // so first start of bot on any new map is not playable
            Map.AnalyzeMap(); // must be called before any Map.* methods


            Logger.AddAndPrint("Assign allUnits");
            List<Unit> allUnits = Game.GetAllUnits();
            foreach (Unit u in allUnits) {
                if (u.IsMine) {
                    if (scv == null && u.UnitTypeEnum == UnitTypes.Terran_SCV) {
                        scv = u;
                        Logger.AddAndPrint("scv found");
                    } else if (commandCenter == null && u.UnitTypeEnum == UnitTypes.Terran_CommandCenter) {
                        commandCenter = u;
                        Logger.AddAndPrint("cc found");
                    }
                }
            }


            // lets send four scv to nearest minerals
            // easy but not optimized variant
            Logger.AddAndPrint("Assign fourScv");
            List<Unit> fourScv = new List<Unit>();
            foreach (Unit u in allUnits) {
                if (u.IsMine && u.UnitTypeEnum == UnitTypes.Terran_SCV) {
                    fourScv.Add(u);
                }
            }

            Logger.AddAndPrint("send four scv");
            List<Unit> allMinerals = Game.GetAllMinerals();
            foreach (Unit scv in fourScv) {
                double minDistance = 0;
                Unit nearestMineral = null;
                foreach (Unit mineral in allMinerals) {
                    double cDistance = scv.GetDistanceToUnit(mineral);
                    if (cDistance < minDistance || nearestMineral == null) {
                        minDistance = cDistance;
                        nearestMineral = mineral;
                    }
                }
                scv.DoRightClick(nearestMineral);
                allMinerals.Remove(nearestMineral);
            }

            //lets build scv
            Logger.AddAndPrint("train scv");
            commandCenter.DoTrainUnit(UnitTypes.Terran_SCV);  // all actions for unit starts with `do`


        }

        public static void OnFrame() {
            int cFrameCount = Game.FrameCount;
            Game.DrawText(DrawPlaces.Screen, 10, 10, cFrameCount.ToString(), DrawTextColors.Teal);
            Game.DrawText(DrawPlaces.Screen, 50, 10, "Map.IsAnalyzed = " + Map.IsAnalyzed);

            // draw build-tiles grid
            for (int x = 0; x <= Game.MapWidthTiles * BuildTile.Width; x += BuildTile.Width) {
                Game.DrawLine(DrawPlaces.Map, x, 0, x, Game.MapHeightTiles * BuildTile.Height, DrawColor.DarkGray);
            }
            for (int y = 0; y <= Game.MapHeightTiles; y++) {
                Game.DrawLine(DrawPlaces.Map, 0, y * BuildTile.Height, Game.MapWidthTiles * BuildTile.Width, y * BuildTile.Height, DrawColor.DarkGray);
            }


            // draw all map regions
            if (Map.IsAnalyzed) {
                List<MapRegion> mapRegions = Map.GetAllMapRegions();
                foreach (var mapRegion in mapRegions) {
                    Game.DrawText(DrawPlaces.Map, mapRegion.Center.X, mapRegion.Center.Y, "region center");
                    Game.DrawMapPolygon(mapRegion.MapPolygon, DrawColor.White);
                }
            }

            // draw some info on Scv and CommandCenter
            if (cFrameCount % 1 == 0 && Map.IsAnalyzed) {
                if (scv != null && commandCenter != null) {
                    // draw attack range of the first scv as white circle
                    Game.DrawCircle(DrawPlaces.Map, scv.Position.X, scv.Position.Y, scv.UnitType.AttackRange, DrawColor.White, false);

                    // draw scv and command center coordinates
                    Game.DrawText(DrawPlaces.Screen, 10, 30, "Scv = " + scv.BuildTile.X + ";" + scv.BuildTile.Y + " valid=" + scv.BuildTile.IsValid);
                    Game.DrawText(DrawPlaces.Screen, 10, 40, "CommandCenter = " + commandCenter.BuildTile.X + ";" + commandCenter.BuildTile.Y + " valid=" + commandCenter.BuildTile.IsValid);


                    double distanceByGround = Map.GetDistanceByGround(scv.BuildTile, commandCenter.BuildTile);
                    double distanceByAir = Map.GetDistanceByAir(scv.BuildTile, commandCenter.BuildTile);
                    Game.DrawText(DrawPlaces.Screen, 10, 50, "CommandCenter to Scv: distanceByGround = " + distanceByGround + "; distanceByAir = " + distanceByAir);

                }
            }

        }

        public static void OnUnitCreate(Unit unit) {
            Logger.AddAndPrint("unit create: " + unit.UnitTypeEnum.ToString());
        }

        public static void OnUnitDestroy(Unit unit) {
            Logger.AddAndPrint("unit destroy: " + unit.UnitTypeEnum.ToString());
        }

        internal static void OnUnitHide(Unit unit) {
            Logger.AddAndPrint("unit hide: " + unit.UnitTypeEnum.ToString());
        }

        internal static void OnUnitMorph(Unit unit) {
            Logger.AddAndPrint("unit morph: " + unit.UnitTypeEnum.ToString());
        }

        internal static void OnUnitShow(Unit unit) {
            Logger.AddAndPrint("unit show: " + unit.UnitTypeEnum.ToString());
        }

        internal static void OnEnd() {
            Logger.AddAndPrint("onEnd: ");
        }
    }
}
